#pragma once

#include "Common.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"

#include <memory>
#include <unordered_map>

class Reactor
{
    static const int revs_num = 128;

private:

    bool _isConnectionExists(int sockfd)
    {
        auto pos = _connections.find(sockfd);
        return pos != _connections.end();
    }

    bool isConnectionExists(std::shared_ptr<Connection> ptr)
    {
        return _isConnectionExists(ptr->getSockfd());
    }

    bool isConnectionExists(int sockfd)
    {
        return _isConnectionExists(sockfd);
    }

    bool isConnectionEmpty() const
    {
        return _connections.empty();
    }

    int loopOnce(int timeout)
    {
        return _epoll_ptr->waitEvent(_revs, revs_num, timeout);
    }
    
    void dispatcher(int num)
    {
        for (int i = 0; i < num; ++i)
        {
            int sockfd = _revs[i].data.fd;
            int revents = _revs[i].events;

            // 1. 将所有的异常处理，统一转化成 IO 错误 
            // 2. 所有的 IO 异常，统一转换成为一个异常处理函数
            if (revents & EPOLLERR)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }
            if (revents & EPOLLHUP)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }

            if (isConnectionExists(sockfd) == false)
            {
                continue;
            }

            if (revents & EPOLLIN)  // 不用区分异常，也不用区分 listener 和 普通 sockfd
            {
                _connections[sockfd]->recver();
            }
            if (revents & EPOLLOUT)
            {
                _connections[sockfd]->sender();
            }
        }
    }
    
public:

    Reactor()
        :_epoll_ptr(std::make_unique<Epoller>())
        ,_isRunning(false)
    {
        ;
    }

    void loop()
    {
        if (isConnectionEmpty() == true)
        {
            return;
        }

        _isRunning = true;
        int timeout = -1;

        while (_isRunning)
        {
            printConnection();

            int n = loopOnce(timeout);

            dispatcher(n);
        }
        _isRunning = false;
    }

    void stop()
    {
        _isRunning = false;
    }

    void enableReadWrite(int sockfd, bool enableRead, bool enableWrite)
    {
        if (isConnectionExists(sockfd) == false)
        {
            return;
        }

        uint32_t newEvent = (EPOLLET | (enableRead ? EPOLLIN : 0) | (enableWrite ? EPOLLOUT:0));

        _connections[sockfd]->setEvent(newEvent);
        _epoll_ptr->setEvent(sockfd, newEvent);
    }

    void addConnection(std::shared_ptr<Connection>& con)
    {
        if (isConnectionExists(con) == true)
        {
            return;
        }

        uint32_t events = con->getEvent();
        int sockfd = con->getSockfd();
        _epoll_ptr->addEvent(sockfd, events);

        con->setOwner(this);

        _connections[sockfd] = con;

        LOG(LogLevel::DEBUG) << "add new client:> " << sockfd;
    }

    void delConnection(int sockfd)
    {
        if (isConnectionExists(sockfd) == false)
        {
            return;
        }

        _epoll_ptr->delEvent(sockfd);
        _connections.erase(sockfd);
        ::close(sockfd);

        LOG(LogLevel::DEBUG) << "client quit:> " << sockfd;
    }

    void printConnection()
    {
        std::cout << "Reactor 正在管理的 fd 有:> ";
        for (auto& e : _connections)
        {
            std::cout << e.second->getSockfd() << " ";
        }
        std::cout << std::endl;
    }

    ~Reactor()
    {
        ;
    }
    
private:

    bool _isRunning;

    // epoll 监听
    std::unique_ptr<Epoller> _epoll_ptr;

    // 一个 Connection 对应一个 fd, 具体连接处理通过容器管理起来
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;

    // 就绪的事件
    struct epoll_event _revs[Reactor::revs_num];    
};
